use std::ffi::CStr;
use std::os::raw::{c_char, c_int};
use std::ptr;

use ratatui::{
    layout::Rect,
    style::{Color, Style},
    text::{Line, Span, Text},
    widgets::{Block, Borders, Paragraph, Widget, List, ListItem, Gauge, Table, Row, Cell},
    Frame,
};

use crate::{RatatuiResult, c_str_to_string};

/// Widget types
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RatatuiWidgetType {
    Text = 0,
    Block = 1,
    Paragraph = 2,
    List = 3,
    Gauge = 4,
    Table = 5,
}

/// Opaque widget handle for FFI
#[repr(C)]
pub struct RatatuiWidget {
    widget_type: RatatuiWidgetType,
    content: String,
    title: Option<String>,
    items: Vec<String>,  // For List widget
    progress: f64,       // For Gauge widget (0.0 to 1.0)
    x: u16,
    y: u16,
    width: u16,
    height: u16,
    visible: bool,       // Widget visibility
    enabled: bool,       // Widget enabled state
    selected: bool,      // Widget selection state
    dirty: bool,         // Whether widget needs redraw
}

impl RatatuiWidget {
    fn new_text(content: String) -> Self {
        RatatuiWidget {
            widget_type: RatatuiWidgetType::Text,
            content,
            title: None,
            items: Vec::new(),
            progress: 0.0,
            x: 0,
            y: 0,
            width: 0,
            height: 0,
            visible: true,
            enabled: true,
            selected: false,
            dirty: true,
        }
    }

    fn new_block(title: String) -> Self {
        RatatuiWidget {
            widget_type: RatatuiWidgetType::Block,
            content: String::new(),
            title: Some(title),
            items: Vec::new(),
            progress: 0.0,
            x: 0,
            y: 0,
            width: 0,
            height: 0,
            visible: true,
            enabled: true,
            selected: false,
            dirty: true,
        }
    }

    fn new_paragraph(content: String) -> Self {
        RatatuiWidget {
            widget_type: RatatuiWidgetType::Paragraph,
            content,
            title: None,
            items: Vec::new(),
            progress: 0.0,
            x: 0,
            y: 0,
            width: 0,
            height: 0,
            visible: true,
            enabled: true,
            selected: false,
            dirty: true,
        }
    }

    fn new_list(items: Vec<String>) -> Self {
        RatatuiWidget {
            widget_type: RatatuiWidgetType::List,
            content: String::new(),
            title: None,
            items,
            progress: 0.0,
            x: 0,
            y: 0,
            width: 0,
            height: 0,
            visible: true,
            enabled: true,
            selected: false,
            dirty: true,
        }
    }

    fn new_gauge(progress: f64) -> Self {
        RatatuiWidget {
            widget_type: RatatuiWidgetType::Gauge,
            content: String::new(),
            title: None,
            items: Vec::new(),
            progress: progress.clamp(0.0, 1.0),
            x: 0,
            y: 0,
            width: 0,
            height: 0,
            visible: true,
            enabled: true,
            selected: false,
            dirty: true,
        }
    }

    pub fn render(&self, frame: &mut Frame, area: Rect) {
        let widget_area = if self.width > 0 && self.height > 0 {
            Rect {
                x: self.x.min(area.width.saturating_sub(1)),
                y: self.y.min(area.height.saturating_sub(1)),
                width: self.width.min(area.width.saturating_sub(self.x)),
                height: self.height.min(area.height.saturating_sub(self.y)),
            }
        } else {
            area
        };

        match self.widget_type {
            RatatuiWidgetType::Text => {
                let text = Text::from(self.content.as_str());
                frame.render_widget(text, widget_area);
            }
            RatatuiWidgetType::Block => {
                let mut block = Block::default().borders(Borders::ALL);
                if let Some(ref title) = self.title {
                    block = block.title(title.as_str());
                }
                frame.render_widget(block, widget_area);
            }
            RatatuiWidgetType::Paragraph => {
                let paragraph = Paragraph::new(self.content.as_str());
                frame.render_widget(paragraph, widget_area);
            }
            RatatuiWidgetType::List => {
                let items: Vec<ListItem> = self.items
                    .iter()
                    .map(|item| ListItem::new(item.as_str()))
                    .collect();
                let mut list = List::new(items);
                if let Some(ref title) = self.title {
                    list = list.block(Block::default().borders(Borders::ALL).title(title.as_str()));
                }
                frame.render_widget(list, widget_area);
            }
            RatatuiWidgetType::Gauge => {
                let mut gauge = Gauge::default()
                    .ratio(self.progress)
                    .label(format!("{:.1}%", self.progress * 100.0));
                if let Some(ref title) = self.title {
                    gauge = gauge.block(Block::default().borders(Borders::ALL).title(title.as_str()));
                }
                frame.render_widget(gauge, widget_area);
            }
            RatatuiWidgetType::Table => {
                // For now, create a simple table from items
                let rows: Vec<Row> = self.items
                    .iter()
                    .map(|item| Row::new(vec![Cell::from(item.as_str())]))
                    .collect();
                let mut table = Table::new(rows, [ratatui::layout::Constraint::Percentage(100)]);
                if let Some(ref title) = self.title {
                    table = table.block(Block::default().borders(Borders::ALL).title(title.as_str()));
                }
                frame.render_widget(table, widget_area);
            }
        }
    }

    fn set_position(&mut self, x: u16, y: u16) {
        self.x = x;
        self.y = y;
    }

    fn set_size(&mut self, width: u16, height: u16) {
        self.width = width;
        self.height = height;
    }
}

/// Create a new text widget
#[no_mangle]
pub extern "C" fn ratatui_text_new(content: *const c_char) -> *mut RatatuiWidget {
    if content.is_null() {
        return ptr::null_mut();
    }

    unsafe {
        match c_str_to_string(content) {
            Ok(content_str) => {
                let widget = RatatuiWidget::new_text(content_str);
                Box::into_raw(Box::new(widget))
            }
            Err(_) => ptr::null_mut(),
        }
    }
}

/// Create a new block widget
#[no_mangle]
pub extern "C" fn ratatui_block_new(title: *const c_char) -> *mut RatatuiWidget {
    if title.is_null() {
        return ptr::null_mut();
    }

    unsafe {
        match c_str_to_string(title) {
            Ok(title_str) => {
                let widget = RatatuiWidget::new_block(title_str);
                Box::into_raw(Box::new(widget))
            }
            Err(_) => ptr::null_mut(),
        }
    }
}

/// Create a new paragraph widget
#[no_mangle]
pub extern "C" fn ratatui_paragraph_new(content: *const c_char) -> *mut RatatuiWidget {
    if content.is_null() {
        return ptr::null_mut();
    }

    unsafe {
        match c_str_to_string(content) {
            Ok(content_str) => {
                let widget = RatatuiWidget::new_paragraph(content_str);
                Box::into_raw(Box::new(widget))
            }
            Err(_) => ptr::null_mut(),
        }
    }
}

/// Free a widget
#[no_mangle]
pub extern "C" fn ratatui_widget_free(widget: *mut RatatuiWidget) {
    if !widget.is_null() {
        unsafe {
            let _ = Box::from_raw(widget);
        }
    }
}

/// Set widget position
#[no_mangle]
pub extern "C" fn ratatui_widget_set_position(
    widget: *mut RatatuiWidget,
    x: u16,
    y: u16,
) -> c_int {
    if widget.is_null() {
        return RatatuiResult::ErrorNullPointer as c_int;
    }

    unsafe {
        let widget = &mut *widget;
        widget.set_position(x, y);
        RatatuiResult::Ok as c_int
    }
}

/// Set widget size
#[no_mangle]
pub extern "C" fn ratatui_widget_set_size(
    widget: *mut RatatuiWidget,
    width: u16,
    height: u16,
) -> c_int {
    if widget.is_null() {
        return RatatuiResult::ErrorNullPointer as c_int;
    }

    unsafe {
        let widget = &mut *widget;
        widget.set_size(width, height);
        RatatuiResult::Ok as c_int
    }
}

/// Get widget content
#[no_mangle]
pub extern "C" fn ratatui_widget_get_content(widget: *const RatatuiWidget) -> *mut c_char {
    if widget.is_null() {
        return ptr::null_mut();
    }

    unsafe {
        let widget = &*widget;
        crate::string_to_c_str(&widget.content)
    }
}

/// Create a new list widget
#[no_mangle]
pub extern "C" fn ratatui_list_new() -> *mut RatatuiWidget {
    let widget = RatatuiWidget::new_list(Vec::new());
    Box::into_raw(Box::new(widget))
}

/// Add item to list widget
#[no_mangle]
pub extern "C" fn ratatui_list_add_item(widget: *mut RatatuiWidget, item: *const c_char) -> c_int {
    if widget.is_null() || item.is_null() {
        return RatatuiResult::ErrorNullPointer as c_int;
    }

    unsafe {
        let widget = &mut *widget;
        if widget.widget_type != RatatuiWidgetType::List {
            return RatatuiResult::ErrorInvalidArgument as c_int;
        }

        match c_str_to_string(item) {
            Ok(item_str) => {
                widget.items.push(item_str);
                RatatuiResult::Ok as c_int
            }
            Err(e) => e as c_int,
        }
    }
}

/// Set list widget title
#[no_mangle]
pub extern "C" fn ratatui_list_set_title(widget: *mut RatatuiWidget, title: *const c_char) -> c_int {
    if widget.is_null() || title.is_null() {
        return RatatuiResult::ErrorNullPointer as c_int;
    }

    unsafe {
        let widget = &mut *widget;
        if widget.widget_type != RatatuiWidgetType::List {
            return RatatuiResult::ErrorInvalidArgument as c_int;
        }

        match c_str_to_string(title) {
            Ok(title_str) => {
                widget.title = Some(title_str);
                RatatuiResult::Ok as c_int
            }
            Err(e) => e as c_int,
        }
    }
}

/// Create a new gauge widget
#[no_mangle]
pub extern "C" fn ratatui_gauge_new(progress: f64) -> *mut RatatuiWidget {
    let widget = RatatuiWidget::new_gauge(progress);
    Box::into_raw(Box::new(widget))
}

/// Set gauge progress (0.0 to 1.0)
#[no_mangle]
pub extern "C" fn ratatui_gauge_set_progress(widget: *mut RatatuiWidget, progress: f64) -> c_int {
    if widget.is_null() {
        return RatatuiResult::ErrorNullPointer as c_int;
    }

    unsafe {
        let widget = &mut *widget;
        if widget.widget_type != RatatuiWidgetType::Gauge {
            return RatatuiResult::ErrorInvalidArgument as c_int;
        }

        widget.progress = progress.clamp(0.0, 1.0);
        RatatuiResult::Ok as c_int
    }
}

/// Set gauge title
#[no_mangle]
pub extern "C" fn ratatui_gauge_set_title(widget: *mut RatatuiWidget, title: *const c_char) -> c_int {
    if widget.is_null() || title.is_null() {
        return RatatuiResult::ErrorNullPointer as c_int;
    }

    unsafe {
        let widget = &mut *widget;
        if widget.widget_type != RatatuiWidgetType::Gauge {
            return RatatuiResult::ErrorInvalidArgument as c_int;
        }

        match c_str_to_string(title) {
            Ok(title_str) => {
                widget.title = Some(title_str);
                RatatuiResult::Ok as c_int
            }
            Err(e) => e as c_int,
        }
    }
}

/// Create a new table widget
#[no_mangle]
pub extern "C" fn ratatui_table_new() -> *mut RatatuiWidget {
    let mut widget = RatatuiWidget::new_list(Vec::new());
    widget.widget_type = RatatuiWidgetType::Table;
    Box::into_raw(Box::new(widget))
}

/// Add row to table widget
#[no_mangle]
pub extern "C" fn ratatui_table_add_row(widget: *mut RatatuiWidget, row_data: *const c_char) -> c_int {
    if widget.is_null() || row_data.is_null() {
        return RatatuiResult::ErrorNullPointer as c_int;
    }

    unsafe {
        let widget = &mut *widget;
        if widget.widget_type != RatatuiWidgetType::Table {
            return RatatuiResult::ErrorInvalidArgument as c_int;
        }

        match c_str_to_string(row_data) {
            Ok(row_str) => {
                widget.items.push(row_str);
                RatatuiResult::Ok as c_int
            }
            Err(e) => e as c_int,
        }
    }
}

/// Set table title
#[no_mangle]
pub extern "C" fn ratatui_table_set_title(widget: *mut RatatuiWidget, title: *const c_char) -> c_int {
    if widget.is_null() || title.is_null() {
        return RatatuiResult::ErrorNullPointer as c_int;
    }

    unsafe {
        let widget = &mut *widget;
        if widget.widget_type != RatatuiWidgetType::Table {
            return RatatuiResult::ErrorInvalidArgument as c_int;
        }

        match c_str_to_string(title) {
            Ok(title_str) => {
                widget.title = Some(title_str);
                RatatuiResult::Ok as c_int
            }
            Err(e) => e as c_int,
        }
    }
}

/// Set widget visibility
#[no_mangle]
pub extern "C" fn ratatui_widget_set_visible(widget: *mut RatatuiWidget, visible: bool) -> c_int {
    if widget.is_null() {
        return RatatuiResult::ErrorNullPointer as c_int;
    }

    unsafe {
        let widget = &mut *widget;
        widget.visible = visible;
        widget.dirty = true;
        RatatuiResult::Ok as c_int
    }
}

/// Get widget visibility
#[no_mangle]
pub extern "C" fn ratatui_widget_is_visible(widget: *const RatatuiWidget) -> bool {
    if widget.is_null() {
        return false;
    }

    unsafe {
        let widget = &*widget;
        widget.visible
    }
}

/// Set widget enabled state
#[no_mangle]
pub extern "C" fn ratatui_widget_set_enabled(widget: *mut RatatuiWidget, enabled: bool) -> c_int {
    if widget.is_null() {
        return RatatuiResult::ErrorNullPointer as c_int;
    }

    unsafe {
        let widget = &mut *widget;
        widget.enabled = enabled;
        widget.dirty = true;
        RatatuiResult::Ok as c_int
    }
}

/// Get widget enabled state
#[no_mangle]
pub extern "C" fn ratatui_widget_is_enabled(widget: *const RatatuiWidget) -> bool {
    if widget.is_null() {
        return false;
    }

    unsafe {
        let widget = &*widget;
        widget.enabled
    }
}

/// Set widget selected state
#[no_mangle]
pub extern "C" fn ratatui_widget_set_selected(widget: *mut RatatuiWidget, selected: bool) -> c_int {
    if widget.is_null() {
        return RatatuiResult::ErrorNullPointer as c_int;
    }

    unsafe {
        let widget = &mut *widget;
        widget.selected = selected;
        widget.dirty = true;
        RatatuiResult::Ok as c_int
    }
}

/// Get widget selected state
#[no_mangle]
pub extern "C" fn ratatui_widget_is_selected(widget: *const RatatuiWidget) -> bool {
    if widget.is_null() {
        return false;
    }

    unsafe {
        let widget = &*widget;
        widget.selected
    }
}

/// Check if widget needs redraw
#[no_mangle]
pub extern "C" fn ratatui_widget_is_dirty(widget: *const RatatuiWidget) -> bool {
    if widget.is_null() {
        return false;
    }

    unsafe {
        let widget = &*widget;
        widget.dirty
    }
}

/// Mark widget as clean (no redraw needed)
#[no_mangle]
pub extern "C" fn ratatui_widget_mark_clean(widget: *mut RatatuiWidget) -> c_int {
    if widget.is_null() {
        return RatatuiResult::ErrorNullPointer as c_int;
    }

    unsafe {
        let widget = &mut *widget;
        widget.dirty = false;
        RatatuiResult::Ok as c_int
    }
}
